#nullable disable

namespace Crux.Core.Reflections;
/// <summary>
/// TypeFinder
/// </summary>
public class TypeFinder(IAssemblyFinder assemblyFinder) : ITypeFinder
{
    #region static properties

    #endregion

    #region private fields

    #endregion  private fields

    #region .ctor
    private RuntimeTypeHandle[] _types;

    #endregion .ctor

    #region implements
    /// <inheritdoc/>
    public Type[] Find(Func<Type, bool> predicate) => this.GetAllTypes().Where(predicate).ToArray();
    /// <inheritdoc/>
    public Type[] FindAll() => GetAllTypes();

    #endregion implements
    #region private methods

    private Type[] GetAllTypes()
    {
        if (_types is not null)
            return _types.Select(Type.GetTypeFromHandle).ToArray();

        lock (this)
        {
            _types ??= CreateTypeList().ToArray();
        }

        return _types.Select(Type.GetTypeFromHandle).ToArray();
    }
    private List<RuntimeTypeHandle> CreateTypeList()
    {
        var allTypes = new List<RuntimeTypeHandle>();

        var assemblies = assemblyFinder.GetAssemblies().Distinct();

        foreach (var assembly in assemblies)
        {
            try
            {
                Type[] typesInThisAssembly;
                try
                {
                    typesInThisAssembly = assembly.GetTypes();
                }
                catch (ReflectionTypeLoadException ex)
                {
                    typesInThisAssembly = ex.Types;
                }
                if (typesInThisAssembly.Length == 0 || typesInThisAssembly.Any(p => p is null))
                {
                    continue;
                }

                allTypes.AddRange(typesInThisAssembly.Where(type => type is not null).Select(p => p!.TypeHandle));
            }
            catch (Exception)
            {
            }
        }

        return allTypes;
    }
    #endregion private methods

}